import tkinter  # GUI库
import random  # 随机库
import math  # 数学库
import _thread  # 多线程库
import time  # 时间库

WINDOW_HEIGHT = 480  # 设置窗口高度
WINDOW_WIDTH = 640  # 设置窗口宽度

OUTWALL_THICKNESS = 3  # 设置爱心外壁厚度
FRAME_NUM = 20  # 设置总共的帧数，帧数越大，渲染速度越慢
MIDDLE_SIZE = 10  # 设置爱心大小的中间值
FRAME_TIME = 0  # 设置帧与帧之间的时间间隔，单位：秒
COLOR = "#ff7171"  # 设置爱心颜色
BACK_COLOR = "black"  # 设置背景颜色

Rendering_degree = 270  # 设置每帧的点的个数的最大值


def Heart_Fun(t, size):  # 计算爱心坐标的函数

    # ----------------爱心的函数----------------
    x = 16 * (math.sin(t) ** 3)
    y = -(13 * math.cos(t) - 5 * math.cos(2 * t) -
          2 * math.cos(3 * t) - math.cos(4 * t))
    # -----------------------------------------

    # ----------------整体扩大size倍----------------
    x *= size
    y *= size
    # ---------------------------------------------

    # ----------------使爱心居中展示----------------
    x += WINDOW_WIDTH / 2
    y += WINDOW_HEIGHT / 2
    # ---------------------------------------------

    return int(x), int(y)  # 返回坐标


def Make_Frame(frameNum: int):  # 生成各帧的函数
    framePackage = []  # 用来存储帧的各点的数据
    Loop = True  # 是否生成完成
    i = 0
    while Loop:
        size = MIDDLE_SIZE + math.sin(i)  # 利用正弦函数的周期性来制造跳动效果
        Heart_Point = []  # 其中一帧的点的集合
        old_k = []  # 随机到的点的记录
        if i >= 2 * math.pi:  # 判断函数是否完成一个周期，若完成则不再继续生成
            Loop = False
        for j in range(Rendering_degree):  # 生成其中一帧的点的坐标集合
            k = random.uniform(0, 2 * math.pi)  # 在0到2*pi中随机一个小数
            if not k in old_k:  # 判断当前小数是否曾经被随机过，如果没有，则将点记录下来
                x, y = Heart_Fun(k, size)  # 利用函数生成坐标
                point = [x, y]  # 记录坐标
                Heart_Point.append(point)  # 存入当前帧的数据
        framePackage.append(Heart_Point)  # 将一帧的所以数据添加至各帧的集合
        i += 2 * math.pi / frameNum  # 根据帧数和三角函数的性质，生成每次i的取值增加量，即Δi
    return framePackage  # 返回帧数据


def draw(data: list):  # 用于绘制的函数
    while True:
        for i in range(len(data)):  # 根据帧数进行逐帧绘制
            canvas.delete("all")  # 清屏
            for j in range(int(len(data[i])/2)):  # 为加快绘制速度，采用“向中方法”绘制
                canvas.create_rectangle(data[i][j][0], data[i][j][1], data[i][j][0] +
                                        OUTWALL_THICKNESS, data[i][j][1] + OUTWALL_THICKNESS, width=0, fill=COLOR)  # 列表中左侧像素点的描绘
                canvas.create_rectangle(data[i][-j][0], data[i][-j][1], data[i][-j][0] +
                                        OUTWALL_THICKNESS, data[i][-j][1] + OUTWALL_THICKNESS, width=0, fill=COLOR)  # 列表中右侧像素点的描绘
            time.sleep(FRAME_TIME)


if __name__ == "__main__":
    root = tkinter.Tk()
    canvas = tkinter.Canvas(root, bg=BACK_COLOR,
                            height=WINDOW_HEIGHT, width=WINDOW_WIDTH)
    canvas.pack()
    data = Make_Frame(FRAME_NUM)  # 生成各帧的各点的坐标集合
    _thread.start_new_thread(draw, (data,))  # 启用另一线程进行绘制
    root.mainloop()  # GUI主循环


# ================“向中方法”解读=================
#   向中方法即绘制时从左向右和从右向左同时绘制，
# 或经过一次循环可以绘制两个坐标点，可以大大缩短
# 绘制时间，增加效率
# ==============================================
